import backtrader as bt
import pandas as pd
import numpy as np
import tushare as ts

'''Indicators指标调用

backtrader回测框架内置了很多技术分析指标，封装在indicators中。打开backtrader安装路径，以Anaconda为例，
打开\Lib\site-packages\backtrader\，进入indicators文件夹，可以看到里面有48个py文件，文件名是各个技术指标或公示的简称，
打开这些文件可以进一步了解包含的具体指标，以及调用的函数名和参数等。

以MACD指标为例，打开macd.py文件，可以看到MACD和MACDHisto两个类，其中MACD是计算MACD指标的类，而MACDHisto则是MACD的子类，
增加了macd和信号线之间差异的“直方图”，调用的时候直接使用bt.ind.MACD(参数)。下面以常用的MACD指标为例，为大家展示其调用方法。
'''


def get_data(code,start='2010-01-01',end='2020-08-31'):
    df=ts.get_k_data(code,autype='qfq',start=start,end=end)
    df.index=pd.to_datetime(df.date)
    df['openinterest']=0
    df=df[['open','high','low','close','volume','openinterest']]
    return df

def main(data,strategy,pf=False):
    cerebro = bt.Cerebro()
    feed = bt.feeds.PandasData(dataname=data)
    cerebro.adddata(feed)
    #加载策略
    cerebro.addstrategy(strategy)
    # 设置初始资本为10,000
    startcash = 100000
    cerebro.broker.setcash(startcash)
    # 设置交易手续费为 0.1%
    cerebro.broker.setcommission(commission=0.001)
    cerebro.run()
    #获取回测结束后的总资金
    portvalue = cerebro.broker.getvalue()
    pnl = portvalue - startcash
    if pf:
        print(f'总资金: {round(portvalue,2)}')
        print(f'净收益: {round(pnl,2)}')

    cerebro.plot()

#以MACD指标为例，调用该指标计算MACD柱，当MACD柱大于0（金叉）时发出买入信号，当MACD柱小于0（死叉）时发出卖出信号。
class TradeStrategy(bt.Strategy):
    params=(('p1',12),('p2',26),('p3',9),)
    def __init__(self):
        self.order = None
        #获取MACD柱
        self.macdhist = bt.ind.MACDHisto(self.data,
                        period_me1=self.p.p1,
                        period_me2=self.p.p2,
                        period_signal=self.p.p3)
    def next(self):
        if not self.position:
            # 得到当前的账户价值
            total_value = self.broker.getvalue()
            #1手=100股，满仓买入
            ss=int((total_value/100)/self.datas[0].close[0])*100
            #当MACD柱大于0（红柱）且无持仓时满仓买入
            if self.macdhist > 0:
                self.order=self.buy(size=ss)
        else:
            #当MACD柱小于0（绿柱）且持仓时全部清仓
            if self.macdhist < 0:
                self.close()

#以中国平安股票为例，使用MACD指标对2010.1-2020.9年数据进行历史回测。
data = get_data('601318', '2010-03-01')
main(data, TradeStrategy, pf=True)

